package org.ldx.lotterysystem.service.impl;

import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.ldx.lotterysystem.common.errorcode.ServiceErrorCodeConstants;
import org.ldx.lotterysystem.common.exception.ServiceException;
import org.ldx.lotterysystem.common.utils.JacksonUtil;
import org.ldx.lotterysystem.common.utils.RedisUtil;
import org.ldx.lotterysystem.controller.param.DrawPrizeParam;
import org.ldx.lotterysystem.controller.param.ShowWinningRecordsParam;
import org.ldx.lotterysystem.dao.dataobject.*;
import org.ldx.lotterysystem.dao.mapper.*;
import org.ldx.lotterysystem.service.DrawPrizeService;
import org.ldx.lotterysystem.service.PrizeService;
import org.ldx.lotterysystem.service.dto.WinningRecordDTO;
import org.ldx.lotterysystem.service.enums.ActivityPrizeStatusEnum;
import org.ldx.lotterysystem.service.enums.ActivityPrizeTiersEnum;
import org.ldx.lotterysystem.service.enums.ActivityStatusEnum;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

import static org.ldx.lotterysystem.common.config.DirectRabbitConfig.EXCHANGE_NAME;
import static org.ldx.lotterysystem.common.config.DirectRabbitConfig.ROUTING;
@Slf4j
@Service
public class DrawPrizeServiceImpl implements DrawPrizeService {
    //过期时间
    private final Long WINNING_RECORD_TIMEOUT = 60*60*24*2L;
    private final String WINNING_RECORD_PREFIX ="WINNING_RECORDS_";
    @Resource
    private RabbitTemplate rabbitTemplate;
    @Resource
    ActivityMapper activityMapper;
    @Resource
    ActivityPrizeMapper activityPrizeMapper;
    @Resource
    UserMapper userMapper;
    @Resource
    PrizeMapper prizeMapper;
    @Resource
    WinnerRecordMapper winnerRecordMapper;
    @Resource
    private RedisUtil redisUtil;
    @Override
    public void drawPrize(DrawPrizeParam param) {
        Map<String,String> map = new HashMap<>();
        map.put("messageId",String.valueOf(UUID.randomUUID()));
        map.put("messageData", JacksonUtil.writeValueAsString(param));
        //发消息 :交换机,绑定的key(队列)，消息体
        rabbitTemplate.convertAndSend(EXCHANGE_NAME,ROUTING,map);
        log.info("MQ消息发送成功 map={}",JacksonUtil.writeValueAsString(param));
    }

    @Override
    public Boolean checkDrawPrizeParam(DrawPrizeParam param) {
        ActivityDo activityDo = activityMapper.selectById(param.getActivityId());
        //根据活动id和奖品id查，可以验证奖品的有效性
        ActivityPrizeDo activityPrizeDo = activityPrizeMapper.selectByAPId(param.getActivityId(),param.getPrizeId());
        //活动和奖品是否存在
        if(null == activityDo || null == activityPrizeDo){
            //throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_OR_PRIZE_NULL);
            log.info("校验参数错误，原因：{}",ServiceErrorCodeConstants.ACTIVITY_OR_PRIZE_NULL.getMsg());
            return false;
        }
        //活动是否有效
        if(activityDo.getStatus().equalsIgnoreCase(ActivityStatusEnum.COMPLETE.name())){
           // throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_COMPLETED);
            log.info("校验参数错误，原因：{}",ServiceErrorCodeConstants.ACTIVITY_COMPLETED.getMsg());
            return false;
        }
        //奖品是否有效
        if(activityPrizeDo.getStatus().equalsIgnoreCase(ActivityPrizeStatusEnum.COMPLETE.name())){
            //throw new ServiceException(ServiceErrorCodeConstants.PRIZE_COMPLETED);
            log.info("校验参数错误，原因：{}",ServiceErrorCodeConstants.PRIZE_COMPLETED.getMsg());
            return false;
        }
        //中奖人数是否和奖品数量一致
        if(activityPrizeDo.getPrizeAmount()!=param.getWinnerList().size()){
           // throw new ServiceException(ServiceErrorCodeConstants.WINNER_PRIZE_ERROR);
            log.info("校验参数错误，原因：{}",ServiceErrorCodeConstants.WINNER_PRIZE_ERROR.getMsg());
            return false;
        }
        return true;
    }

    @Override
    public List<WinningRecordDO> saveWinnerRecords(DrawPrizeParam param) {
        //查询相关信息
        //查询活动信息
        ActivityDo activityDo = activityMapper.selectById(param.getActivityId());
        //查询中奖者基本信息
        List<UserDo> userDoList = userMapper.batchSelectById(param.getWinnerList().stream().
                map(DrawPrizeParam.Winner::getUserId).collect(Collectors.toList()));
        //查询奖品信息
        PrizeDo prizeDo = prizeMapper.selectById(param.getPrizeId());
        //查询活动奖品关联表（获取奖品等级）
        ActivityPrizeDo activityPrizeDo = activityPrizeMapper.selectByAPId(param.getActivityId(), param.getPrizeId());
        //构造中奖者记录，保存
        List<WinningRecordDO> winningRecordDOList = userDoList.stream()
                .map(userDo -> {
                    WinningRecordDO winningRecordDO = new WinningRecordDO();
                    winningRecordDO.setActivityId(activityDo.getId());
                    winningRecordDO.setActivityName(activityDo.getActivityName());
                    winningRecordDO.setPrizeId(prizeDo.getId());
                    winningRecordDO.setPrizeName(prizeDo.getName());
                    winningRecordDO.setPrizeTier(ActivityPrizeTiersEnum.forName(activityPrizeDo.getPrizeTiers()).getMessage());
                    winningRecordDO.setWinnerId(userDo.getId());
                    winningRecordDO.setWinnerName(userDo.getUserName());
                    winningRecordDO.setWinnerEmail(userDo.getEmail());
                    winningRecordDO.setWinnerPhoneNumber(userDo.getPhoneNumber());
                    winningRecordDO.setWinningTime(param.getWinningTime());
                    return winningRecordDO;

                }).collect(Collectors.toList());
        //保存
        winnerRecordMapper.batchInsert(winningRecordDOList);
        //缓存中奖者信息

        //缓存奖品维度的中奖信息（activityId_prizeId,winningRecordDOList）
        catchWinningRecords(param.getActivityId()+"_"+param.getPrizeId(),winningRecordDOList,WINNING_RECORD_TIMEOUT);

        //缓存活动维度的中奖信息(WinningRecord_activityId,winningRecordDOList)
        //用以显示活动完成后的整体中奖名单
        //当前活动已完成再去存放
        if (activityDo.getStatus().equalsIgnoreCase(ActivityStatusEnum.COMPLETE.name())){
            List<WinningRecordDO> allList = winnerRecordMapper.selectByActivityId(activityDo.getId());
            catchWinningRecords(String.valueOf(param.getActivityId())
                    ,allList,WINNING_RECORD_TIMEOUT);
        }

        return winningRecordDOList;
    }

    @Override
    public void deleteRecords(Long activityId, Long prizeId) {
        if(null==activityId){
            log.warn("要删除中奖记录的活动id为空");
            return;
        }
        //删除数据表
        winnerRecordMapper.deleteRecords(activityId,prizeId);
        //删除缓存(奖品维度，活动维度)
        if(null!=prizeId){
            //删除奖品维度的缓存
            deleteWinningRecords(activityId+"_"+prizeId);
        }
        deleteWinningRecords(String.valueOf(activityId));
    }

    @Override
    public List<WinningRecordDTO> getRecords(ShowWinningRecordsParam param) {
        String key = null;
        if(null == param.getPrizeId()){
            key = String.valueOf(param.getActivityId());
        }
        else
        {key = param.getActivityId()+"_"+param.getPrizeId();}
        //System.out.println(key);
        //先去redis中查询
        List<WinningRecordDO> winningRecords = getWinningRecords(key);
        if(!CollectionUtils.isEmpty(winningRecords)){
            return converToWinningRecordDTO(winningRecords);
        }
        //redis不存在查库并存放在redis中
        List<WinningRecordDO> winningRecordDOList =
                winnerRecordMapper.selectByActivityIdOrPrizeId(param.getActivityId(),param.getPrizeId());
        if(CollectionUtils.isEmpty(winningRecordDOList)){
            log.info("查询的中奖记录为空");
            return Arrays.asList();
        }
        catchWinningRecords(key,winningRecordDOList,WINNING_RECORD_TIMEOUT);
        return converToWinningRecordDTO(winningRecordDOList);
    }

    private List<WinningRecordDTO> converToWinningRecordDTO(List<WinningRecordDO> winningRecords) {
        return winningRecords.stream()
                .map(winningRecordDO -> {
                    WinningRecordDTO result = new WinningRecordDTO();
                    result.setWinnerId(winningRecordDO.getWinnerId());
                    result.setWinnerName(winningRecordDO.getWinnerName());
                    result.setPrizeName(winningRecordDO.getPrizeName());
                    result.setPrizeTier(ActivityPrizeTiersEnum.forName(winningRecordDO.getPrizeTier()));
                    result.setWinningTime(winningRecordDO.getWinningTime());
                    return result;

                }).collect(Collectors.toList());
    }

    private void deleteWinningRecords(String key) {
        try {
            if(redisUtil.hasKey(WINNING_RECORD_PREFIX+key)){
                redisUtil.del(WINNING_RECORD_PREFIX+key);
            }
        }catch (Exception e){
            log.error("删除中奖记录缓存异常 key{}",key);
        }
    }

    /**
     * 缓存中奖记录
     * @param s
     * @param winningRecordDOList
     * @param winningRecordTimeout
     */
    private void catchWinningRecords(String s, List<WinningRecordDO> winningRecordDOList, Long winningRecordTimeout) {

        String key = WINNING_RECORD_PREFIX + s;
        String value = JacksonUtil.writeValueAsString(winningRecordDOList);
        if(!StringUtils.hasText(s)|| CollectionUtils.isEmpty(winningRecordDOList)){
            log.warn("要缓存的值为空");
            return;
        }
        try {
            redisUtil.set(key,value,winningRecordTimeout);
        }catch (Exception e){
            log.error("缓存中奖记录失败 key{},value{}",key,value);
        }
    }

    /**
     * 获取中奖记录
     * @param s
     * @return
     */
    private List<WinningRecordDO> getWinningRecords(String s){
        String key = WINNING_RECORD_PREFIX + s;
        if(!StringUtils.hasText(s)){
            log.warn("要从缓存中获取的的key为空");
            return null;
        }
        String value;
        try{
            value = redisUtil.get(key);
        }catch (Exception e){
            log.error("从缓存中查询异常key{}",key);
            return null;
        }
        // 关键修改：判断value是否为null或空字符串，避免传入null给Jackson
        if (value == null || value.trim().isEmpty()) {
            log.info("Redis中key:{}对应的value为空，返回空列表", key);
            return Collections.emptyList(); // 返回空列表而非null，避免上层处理null的麻烦
        }


        return JacksonUtil.readListValue(value, WinningRecordDO.class);

    }

}
